package com.jxin.mall.weixin.domain.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.jxin.mall.middle.util.redis.RedisUtil;
import com.jxin.mall.weixin.consts.ServiceLogMsgConsts;
import com.jxin.mall.weixin.domain.consts.RedisKeyConsts;
import com.jxin.mall.weixin.domain.entity.service.TuLingRequestBody;
import com.jxin.mall.weixin.domain.entity.service.TuLingResponseBody;
import com.jxin.mall.weixin.domain.exception.RouteOutMsgException;
import com.jxin.mall.weixin.domain.service.WxPortalMsgService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 微信消息处理类
 * @author  蔡佳新
 * @version 1.0
 * @since   jdk 1.8
 */
@Service("wxPortalMsgService")
@Slf4j
public class WxPortalMsgServiceImpl implements WxPortalMsgService {
    /**正则表达式*/
    @Value("${portal.phone.match}")
    private String PHONE_MATCH;
    /**随机数的个数*/
    private static final Integer NUM_SIZE = 4;
    /**注册code消息文本*/
    @Value("${portal.sign.msg}")
    private String SIGN_MSG_TMP;
    /**注册code已经存在消息文本*/
    @Value("${portal.sign.exist}")
    private String SIGN_EXIST_TMP;
    /**注册key的超时时间*/
    @Value("${portal.sign.ttl}")
    private Long SIGN_KEY_TTL;
    @Value("${tl.apiKey}")
    private String API_KEY;
    @Value("${tl.userId}")
    private String USER_ID;
    /**
     * 输入类型:0-文本(默认)、1-图片、2-音频
     * 请求类型默认文本
     */
    private static final int REQ_TYPE = 0;
    /**图灵的API URL*/
    private static final String TU_LING_API_URL = "http://openapi.tuling123.com/openapi/api/v2";
    @Resource(name = "strProtoRedisUtil")
    private RedisUtil strProtoRedisUtil;
    @Override
    public String routeOutMsg(String msgContent) {
        if(ReUtil.isMatch(PHONE_MATCH, msgContent)){
            return getSignCodeByPhone(msgContent);
        }
       return getTuLingResponse(msgContent);
    }

    /**
     * 获得图灵机器人回话
     * @param msgContent 消息正文
     * @throws RouteOutMsgException 调图灵的api接口失败
     * @return 图灵机器人回话
     */
    private String getTuLingResponse(String msgContent) throws RouteOutMsgException{
        final TuLingRequestBody tuLingRequestBody =
                TuLingRequestBody.builder()
                                 .userInfo(TuLingRequestBody.UserInfo.builder().apiKey(API_KEY).userId(USER_ID).build())
                                 .reqType(REQ_TYPE)
                                 .perception(TuLingRequestBody.Perception.builder()
                                                                         .inputText(TuLingRequestBody.Perception
                                                                                    .creatInputText(msgContent)).build())
                                 .build();
        try {
            final String response = HttpUtil.post(TU_LING_API_URL, JSONUtil.toJsonStr(tuLingRequestBody));
            if(log.isDebugEnabled()){
                log.debug(WxPortalMsgServiceMsg.TL_RESPONSE, msgContent, response);
            }
            final TuLingResponseBody tuLingResponseBody = JSONUtil.toBean(response, TuLingResponseBody.class);
            return CollUtil.getFirst(tuLingResponseBody.getResults()).getValues().getText();
        }catch (Exception e){
           throw  new RouteOutMsgException(WxPortalMsgServiceMsg.TL_API_REQUEST_ERR);
        }
    }

    /**
     * 根据电话号码获取注册码
     * 1.如果注册码存在未过期,则不生成新的注册码,告知用户等时间过后再重试
     * 2.如果注册码不存在,生成注册码消息
     * @param  phone 电话号码
     * @return 1.告知用户等待时间 2.带注册码的消息
     * @throws RouteOutMsgException redis取值或设置异常
     * @author 蔡佳新
     */
    private String getSignCodeByPhone(String phone) throws RouteOutMsgException{
        final String key = RedisKeyConsts.REGISTER_PHONE + phone;
        try {
            if(strProtoRedisUtil.hasKey(key)){
                return StrUtil.format(SIGN_EXIST_TMP, phone, strProtoRedisUtil.getExpire(key));
            }
        }catch (Exception e){
            throw new RouteOutMsgException(WxPortalMsgServiceMsg.DO_HAS_KEY_REDIS_ERR, key, e);
        }

        final String randomCode = RandomUtil.randomNumbers(NUM_SIZE);
        try{
            strProtoRedisUtil.set(key, randomCode, SIGN_KEY_TTL);
        }catch (Exception e){
            throw new RouteOutMsgException(WxPortalMsgServiceMsg.SET_PHONE_KEY_ERR, key, e);
        }
        return StrUtil.format(SIGN_MSG_TMP, randomCode);
    }


    //---------------------------------------------------logMsg---------------------------------------------------------
    /**
     * 日志信息常量的内部类
     * @author  蔡佳新
     * @version 1.0
     */
    private interface WxPortalMsgServiceMsg{
        String  DO_HAS_KEY_REDIS_ERR = ServiceLogMsgConsts.POTAL_MSG_SERVICE + "校验电话号码是否存在异常,redis的Key为:{}";
        String  SET_PHONE_KEY_ERR = ServiceLogMsgConsts.POTAL_MSG_SERVICE + "设置手机号码的redisKey失败,redis的Key为:{}";
        String  TL_API_REQUEST_ERR = ServiceLogMsgConsts.POTAL_MSG_SERVICE + "请求文本:{}, 图灵机器人接口调用异常";

        String  TL_RESPONSE = ServiceLogMsgConsts.POTAL_MSG_SERVICE + "请求文本为:{},图灵机器人响应数据为:{}";
    }
}
